package com.apache.flow.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import net.sf.json.JSONObject;

import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Results;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.HistoryService;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.history.HistoryActivityInstance;
import org.jbpm.api.history.HistoryActivityInstanceQuery;
import org.jbpm.api.history.HistoryDetail;
import org.jbpm.api.history.HistoryDetailQuery;
import org.jbpm.api.history.HistoryProcessInstance;
import org.jbpm.api.history.HistoryProcessInstanceQuery;
import org.jbpm.api.history.HistoryTask;
import org.jbpm.api.history.HistoryTaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.apache.common.FlowBaseAction;
import com.apache.core.utils.web.struts2.Struts2Utils;
import com.apache.flow.vo.HisActivityVo;
import com.apache.flow.vo.HisDetailVo;
import com.apache.flow.vo.HisProcessInstanceVo;
import com.apache.flow.vo.HisTaskVo;
import com.apache.flow.vo.ProcessDefinitionVo;
import com.apache.tools.NumberUtils;
import com.apache.tools.StrUtil;

@Namespace("/flow/core")
@Results({})
public class FlowQueryAction extends FlowBaseAction {
	private static final long serialVersionUID = 1L;
	/**
	 * 日志
	 */
	private Logger logger = LoggerFactory.getLogger(FlowQueryAction.class);

	/**
	 * 流程引擎
	 */
	@Autowired
	private ProcessEngine processEngine;

	/**
	 * 上传发布流程，必须为zip
	 */
	private File upload;

	/**
	 * 文件名称
	 */
	private String uploadFileName;
	/**
	 * 文件类型
	 */
	private String uploadContentType;

	/**流程发布id*/
	private String deploymentId;
	/**
	 * 流程定义id
	 */
	private String definitionId;

	/**
	 * 流程实例id
	 */
	private String processInstanceId;

	private String rows;

	private String page;

	/**
	 * 发布流程
	 * @return String
	 * @throws IOException 
	 */
	public String deploy() throws IOException {
		//管理流程定义
		RepositoryService repositoryService = processEngine.getRepositoryService();
		try {
			FileInputStream in = new FileInputStream(upload);
			ZipInputStream zis = new ZipInputStream(in);
			repositoryService.createDeployment().addResourcesFromZipInputStream(zis).deploy();
			showOk("发布流程成功！");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			showError("发布流程失败！");
		} catch (IOException e) {
			e.printStackTrace();
			showError("发布流程失败！");
		}
		return null;
	}

	/**
	 * 启动流程实例
	 * <p>启动流程实例应该在业务系统中执行<p>
	 * @return String
	 * @throws IOException 
	 */
	public String start() throws IOException {
		//管理流程实例
		try {
			ExecutionService executionService = processEngine.getExecutionService();
			Map<String, String> variables = new HashMap<String, String>();
			Enumeration<String> names = Struts2Utils.getRequest().getParameterNames();
			while (names.hasMoreElements()) {
				String key = names.nextElement();
				variables.put(key, Struts2Utils.getRequest().getParameter(key));
			}
			executionService.startProcessInstanceById(definitionId, variables);
			showOk("启动流程成功！");
		} catch (Exception e) {
			logger.debug("启动" + definitionId + "的流程实例错误");
			showError("启动流程失败！");
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * 已经发布的流程
	 * @return String
	 */
	public String data() {
		Struts2Utils.getResponse().setContentType("text/html;charset=UTF-8");
		RepositoryService repositoryService = processEngine.getRepositoryService();
		List<ProcessDefinition> pdList = repositoryService.createProcessDefinitionQuery().list();
		List<ProcessDefinitionVo> pdVolist = new ArrayList<ProcessDefinitionVo>();
		for (ProcessDefinition pd : pdList) {
			ProcessDefinitionVo pdVo = new ProcessDefinitionVo();
			pdVo.setId(pd.getId());
			pdVo.setName(pd.getName());
			pdVo.setKey(pd.getKey());
			pdVo.setVersion(pd.getVersion());
			pdVo.setDeploymentId(pd.getDeploymentId());
			pdVo.setDescription(pd.getDescription());
			pdVolist.add(pdVo);
		}
		JSONObject json = new JSONObject();
		json.put("total", pdVolist.size());
		json.put("rows", pdVolist);
		try {
			Struts2Utils.getResponse().getWriter().write(json.toString());
		} catch (IOException e) {
			logger.debug("得到流程定义数据错误" + e);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 删除流程定义
	 * @return String
	 * @throws IOException 
	 */
	public String delete() throws IOException {

		try {
			RepositoryService repositoryService = processEngine.getRepositoryService();
			//此删除会级联删除，即包括发布记录、流程定义记录、流程处理记录、历史数据记录
			repositoryService.deleteDeploymentCascade(deploymentId);
			showOk("删除成功！");
		} catch (IOException e) {
			e.printStackTrace();
			showError("删除失败！");
		}
		return null;
	}

	/**
	 * 恢复流程定义
	 * @return String
	 */
	public String resume() throws IOException {
		try {
			RepositoryService repositoryService = processEngine.getRepositoryService();
			repositoryService.resumeDeployment(deploymentId);
			showOk("恢复流程定义成功！");
		} catch (IOException e) {
			e.printStackTrace();
			showError("恢复流程定义失败！");
		}
		return null;
	}

	/**
	 * 暂停和挂起流程定义
	 * @return String
	 */
	public String suspend() throws IOException {
		try {
			RepositoryService repositoryService = processEngine.getRepositoryService();
			repositoryService.suspendDeployment(deploymentId);
			showOk("暂停流程定义成功！");
		} catch (IOException e) {
			e.printStackTrace();
			showError("暂停流程定义失败！");
		}
		return null;
	}

	/**
	 * 查询流程实例历史表
	 * @return
	 */
	public String histProInstMsg() {
		int pageNo = NumberUtils.getInt(page, 1);
		int pageSize = NumberUtils.getInt(rows, 15);
		int startIndex = (pageNo - 1) * pageSize;

		HistoryService historyService = processEngine.getHistoryService();
		HistoryProcessInstanceQuery historyProcessInstanceQuery = historyService.createHistoryProcessInstanceQuery();
		int sumCount = 0;
		List<HistoryProcessInstance> hisList = null;

		if (StrUtil.isNotNull(processInstanceId)) {//2015-12-29histProInstMsg
			sumCount = historyProcessInstanceQuery.processInstanceId(processInstanceId).list().size();
			hisList = historyProcessInstanceQuery.processInstanceId(processInstanceId)
					.orderDesc(HistoryProcessInstanceQuery.PROPERTY_ID).page(startIndex, pageSize).list();
		} else if (StrUtil.isNotNull(definitionId)) {
			sumCount = historyProcessInstanceQuery.processDefinitionId(definitionId).list().size();
			hisList = historyProcessInstanceQuery.processDefinitionId(definitionId)
					.orderDesc(HistoryProcessInstanceQuery.PROPERTY_ID).page(startIndex, pageSize).list();
		} else {
			sumCount = historyProcessInstanceQuery.list().size();
			hisList = historyProcessInstanceQuery.orderDesc(HistoryProcessInstanceQuery.PROPERTY_ID)
					.page(startIndex, pageSize).list();
		}

		List<HisProcessInstanceVo> hisProVolist = new ArrayList<HisProcessInstanceVo>();
		for (HistoryProcessInstance hpvo : hisList) {
			HisProcessInstanceVo hisProVo = new HisProcessInstanceVo();
			hisProVo.setDuration(hpvo.getDuration());
			if (hpvo.getEndTime() != null) {
				hisProVo.setEndTime(hpvo.getEndTime().toString());
			}
			if (hpvo.getStartTime() != null) {
				hisProVo.setStartTime(hpvo.getStartTime().toString());
			}
			hisProVo.setProcessDefinitionId(hpvo.getProcessDefinitionId());
			hisProVo.setKey(hpvo.getKey());
			hisProVo.setProcessInstanceId(hpvo.getProcessInstanceId());

			hisProVo.setState(hpvo.getState());
			hisProVo.setEndActivityName(hpvo.getEndActivityName());
			hisProVolist.add(hisProVo);
		}
		JSONObject json = new JSONObject();
		json.put("total", sumCount);
		json.put("rows", hisProVolist);
		try {
			Struts2Utils.getResponse().getWriter().write(json.toString());
		} catch (IOException e) {
			logger.debug("得到流程定义数据错误" + e);
			e.printStackTrace();
		}

		return null;
	}

	/**
	 *  流程节点(活动)历史表
	 * @return
	 */
	public String actinstMsg() {
		int pageNo = NumberUtils.getInt(page, 1);
		int pageSize = NumberUtils.getInt(rows, 15);
		int startIndex = (pageNo - 1) * pageSize;

		HistoryService historyService = processEngine.getHistoryService();
		HistoryActivityInstanceQuery historyActivityInstanceQuery = historyService.createHistoryActivityInstanceQuery();
		int sumCount = 0;
		List<HistoryActivityInstance> hisActiList = null;

		if (StrUtil.isNotNull(processInstanceId)) {//2015-12-29actinstMsg
			sumCount = historyActivityInstanceQuery.processInstanceId(processInstanceId).list().size();
			hisActiList = historyActivityInstanceQuery.processInstanceId(processInstanceId).page(startIndex, pageSize)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_EXECUTIONID)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_STARTTIME).list();
		} else if (StrUtil.isNotNull(definitionId)) {
			sumCount = historyActivityInstanceQuery.processDefinitionId(definitionId).list().size();
			hisActiList = historyActivityInstanceQuery.processDefinitionId(definitionId).page(startIndex, pageSize)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_EXECUTIONID)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_STARTTIME).list();
		} else {
			sumCount = historyActivityInstanceQuery.list().size();
			hisActiList = historyActivityInstanceQuery.page(startIndex, pageSize)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_EXECUTIONID)
					.orderDesc(HistoryActivityInstanceQuery.PROPERTY_STARTTIME).list();
		}

		List<HisActivityVo> hisActVolist = new ArrayList<HisActivityVo>();

		for (HistoryActivityInstance hai : hisActiList) {
			HisActivityVo havo = new HisActivityVo();
			havo.setActivityName(hai.getActivityName());
			havo.setDuration(hai.getDuration());
			if (hai.getEndTime() != null) {
				havo.setEndTime(hai.getEndTime().toString());
			}
			if (hai.getStartTime() != null) {
				havo.setStartTime(hai.getStartTime().toString());
			}
			havo.setExecutionId(hai.getExecutionId());
			hisActVolist.add(havo);
		}
		JSONObject json = new JSONObject();
		json.put("total", sumCount);
		json.put("rows", hisActVolist);
		try {
			Struts2Utils.getResponse().getWriter().write(json.toString());
		} catch (IOException e) {
			logger.debug("得到流程定义数据错误" + e);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 *  Task 的历史信息。
	 * @return
	 */
	public String taskMsg() {
		int pageNo = NumberUtils.getInt(page, 1);
		int pageSize = NumberUtils.getInt(rows, 15);
		int startIndex = (pageNo - 1) * pageSize;

		HistoryService historyService = processEngine.getHistoryService();
		HistoryTaskQuery historyTaskQuery = historyService.createHistoryTaskQuery();
		int sumCount = 0;
		List<HistoryTask> histaskiList = null;

		if (StrUtil.isNotNull(processInstanceId)) {//2015-12-29taskMsg
			sumCount = historyTaskQuery.executionId(processInstanceId).list().size();
			histaskiList = historyTaskQuery.executionId(processInstanceId).page(startIndex, pageSize)
					.orderDesc(HistoryTaskQuery.PROPERTY_EXECUTIONID).orderDesc(HistoryTaskQuery.PROPERTY_CREATETIME)
					.list();
		} else {
			sumCount = historyTaskQuery.list().size();
			histaskiList = historyTaskQuery.page(startIndex, pageSize).orderDesc(HistoryTaskQuery.PROPERTY_EXECUTIONID)
					.orderDesc(HistoryTaskQuery.PROPERTY_CREATETIME).list();
		}

		List<HisTaskVo> histaskVolist = new ArrayList<HisTaskVo>();
		for (HistoryTask ht : histaskiList) {
			HisTaskVo htvo = new HisTaskVo();
			if (null != ht.getAssignee() && ht.getAssignee().startsWith(",")) {
				htvo.setAssignee(ht.getAssignee().substring(1, ht.getAssignee().length()));
			} else {
				htvo.setAssignee(ht.getAssignee());
			}

			if (ht.getCreateTime() != null) {
				htvo.setCreateTime(ht.getCreateTime().toString());
			}
			if (ht.getEndTime() != null) {
				htvo.setEndTime(ht.getEndTime().toString());
			}

			htvo.setDuration(ht.getDuration());
			htvo.setExecutionId(ht.getExecutionId());
			htvo.setId(ht.getId());
			htvo.setOutcome(ht.getOutcome());
			htvo.setState(ht.getState());

			histaskVolist.add(htvo);
		}

		JSONObject json = new JSONObject();

		json.put("total", sumCount);
		json.put("rows", histaskVolist);
		try {
			Struts2Utils.getResponse().getWriter().write(json.toString());
		} catch (IOException e) {
			logger.debug("得到流程定义数据错误" + e);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 *   detail历史记录。
	 * @return
	 */
	public String detailMsg() {
		int pageNo = NumberUtils.getInt(page, 1);
		int pageSize = NumberUtils.getInt(rows, 15);
		int startIndex = (pageNo - 1) * pageSize;

		HistoryService historyService = processEngine.getHistoryService();
		HistoryDetailQuery historyDetailQuery = historyService.createHistoryDetailQuery();
		int sumCount = 0;
		List<HistoryDetail> hisdetailiList = null;

		if (StrUtil.isNotNull(processInstanceId)) {//2015-12-29detailMsg
			sumCount = historyDetailQuery.processInstanceId(processInstanceId).list().size();
			hisdetailiList = historyDetailQuery.processInstanceId(processInstanceId).page(startIndex, pageSize)
					.orderDesc(HistoryDetailQuery.PROPERTY_TIME).list();
		} else {
			sumCount = historyDetailQuery.list().size();
			hisdetailiList = historyDetailQuery.page(startIndex, pageSize).orderDesc(HistoryDetailQuery.PROPERTY_TIME)
					.list();
		}

		List<HisDetailVo> hisdetailVolist = new ArrayList<HisDetailVo>();

		for (HistoryDetail ht : hisdetailiList) {
			HisDetailVo hdvo = new HisDetailVo();
			hdvo.setId(ht.getId());
			if (ht.getTime() != null) {
				hdvo.setTime(ht.getTime().toString());
			}
			hdvo.setUserId(ht.getUserId());
			hisdetailVolist.add(hdvo);
		}
		JSONObject json = new JSONObject();
		json.put("total", sumCount);
		json.put("rows", hisdetailVolist);
		try {
			Struts2Utils.getResponse().getWriter().write(json.toString());
		} catch (IOException e) {
			logger.debug("得到流程定义数据错误" + e);
			e.printStackTrace();
		}
		return null;
	}

	public File getUpload() {
		return upload;
	}

	public void setUpload(File upload) {
		this.upload = upload;
	}

	public String getUploadFileName() {
		return uploadFileName;
	}

	public void setUploadFileName(String uploadFileName) {
		this.uploadFileName = uploadFileName;
	}

	public String getUploadContentType() {
		return uploadContentType;
	}

	public void setUploadContentType(String uploadContentType) {
		this.uploadContentType = uploadContentType;
	}

	public String getDefinitionId() {
		return definitionId;
	}

	public void setDefinitionId(String definitionId) {
		this.definitionId = definitionId;
	}

	public String getDeploymentId() {
		return deploymentId;
	}

	public void setDeploymentId(String deploymentId) {
		this.deploymentId = deploymentId;
	}

	public String getRows() {
		return rows;
	}

	public void setRows(String rows) {
		this.rows = rows;
	}

	public String getPage() {
		return page;
	}

	public void setPage(String page) {
		this.page = page;
	}

	public String getProcessInstanceId() {
		return processInstanceId;
	}

	public void setProcessInstanceId(String processInstanceId) {
		this.processInstanceId = processInstanceId;
	}

}
